package DyingBaby.backend.sql;

import java.util.ArrayList;
import java.util.List;
/**
 * 词法分析器
 * 可以识别关键字、标识符、数字、字符串和符号，
 * 并将输入字符串分解为有意义的标记序列
 */
public class Lexer {
    //可识别的标识类型如下
      //IDENT: 标识符（变量名、函数名等）
      //NUMBER: 数字
      //STRING: 字符串
      //SYMBOL: 符号（如 +, -, *, / 等）
      //KEYWORD: 关键字（如 if, else, while 等）
      //EOF: 文件结束标记
    public enum Type { IDENT, NUMBER, STRING, SYMBOL, KEYWORD, EOF }

    //内部类定义Token
    public static class Token {
        public final Type type;//标记的类型
        public final String text;//标记的文本
        public Token(Type type, String text) { this.type = type; this.text = text; }
        public String toString() { return type + ":" + text; }
    }

    private final String s;// 要分析的输入字符串
    private int i = 0;// 当前读取位置的索引

    public Lexer(String s) {
        this.s = s;
    }

    public List<Token> tokenize() {
        List<Token> out = new ArrayList<>();
        Token t;
        while ((t = next()).type != Type.EOF) {
            out.add(t);
        }
        out.add(t);
        return out;
    }

    //核心
      // 跳过空白字符
      //检查是否到达字符串末尾
      //根据当前字符的类型调用相应的读取方法
      //如果都不匹配，则当作符号处理
    private Token next() {
        skipWs();
        if (i >= s.length()) return new Token(Type.EOF, "");
        char c = s.charAt(i);
        if (c == '\'') return readString();
        if (isDigit(c)) return readNumber();
        if (isIdentStart(c)) return readIdentOrKeyword();
        return readSymbol();
    }

    // 读取符号，支持多字符操作符
    private Token readSymbol() {
        char c = s.charAt(i);
        i++;

        // 检查双字符操作符
        if (i < s.length()) {
            char next = s.charAt(i);
            String twoChar = String.valueOf(c) + next;
            switch (twoChar) {
                case "!=":
                case "<>":
                case ">=":
                case "<=":
                    i++; // 消费第二个字符
                    return new Token(Type.SYMBOL, twoChar);
            }
        }

        // 单字符操作符
        return new Token(Type.SYMBOL, String.valueOf(c));
    }

    //跳过空白/分号
    private void skipWs() {
        while (i < s.length()) {
            char c = s.charAt(i);
            if (Character.isWhitespace(c)) { i++; continue; }
            if (c == ';') { i++; continue; }
            break;
        }
    }

    private Token readString() {
        StringBuilder sb = new StringBuilder();
        i++; // skip opening '
        while (i < s.length()) {
            char c = s.charAt(i++);
            if (c == '\'') break;
            sb.append(c);
        }
        return new Token(Type.STRING, sb.toString());
    }

    private Token readNumber() {
        int start = i;
        while (i < s.length() && isDigit(s.charAt(i))) i++;
        return new Token(Type.NUMBER, s.substring(start, i));
    }

    //读取标识符并检查它是否是预定义的关键字
    private Token readIdentOrKeyword() {
        int start = i;
        while (i < s.length() && isIdentPart(s.charAt(i))) i++;
        String word = s.substring(start, i);
        String up = word.toUpperCase();
        switch (up) {
            case "CREATE": case "TABLE": case "PRIMARY": case "KEY": case "INT": case "STRING":
            case "INSERT": case "INTO": case "VALUES": case "SELECT": case "FROM": case "WHERE":
            case "UPDATE": case "SET": case "DELETE": case "AND": case "OR":
                return new Token(Type.KEYWORD, up);
            default:
                return new Token(Type.IDENT, word);
        }
    }

    //下述方法皆为了判断字符的类型
    private boolean isDigit(char c) { return c >= '0' && c <= '9'; }
    private boolean isIdentStart(char c) { return Character.isLetter(c) || c=='_'; }
    private boolean isIdentPart(char c) { return Character.isLetterOrDigit(c) || c=='_'; }
} 